﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include <map>
#include <vector>
#include <string>
#include <math.h>

#ifdef _MSC_VER
# define DLL_EXPORT __declspec(dllexport)
# define DLL_IMPORT __declspec(dllimport)
#else
# define DLL_EXPORT
# define DLL_IMPORT
#endif

#ifdef EXPRENGINE_EXPORTS
#define EXPR_UNITMAP_API DLL_EXPORT
#else
#define EXPR_UNITMAP_API DLL_IMPORT
#endif

//必读，注意事项2018.6.14 丁勇
//1.赋值顺序不能变动，逻辑按照顺序进行判断处理，为的是之后方便单位扩展
//2.序号从EUT_Num到EUT_Double之间添加自然单位，是可进行计算的
enum ExprUnitType
{
    EUT_Invalid = 0,
    //能计算的从01开始
    EUT_Num,//数据，对应界面输入的数据 ex：1.3、10
    EUT_Length,
    EUT_Angle,
    EUT_Time,
    //如果还需要添加，从此处开始

    EUT_Int,//2018-9-28，因发版紧急需求10801，目前只对EUT_Double取整时使用。
    EUT_Double,//对应界面输入的整数、数值
    //不能计算的从EUT_Bool开始
    EUT_Bool,
    EUT_String,
};

// 表达式单位容器类
class EXPR_UNITMAP_API UnitMap
{
public:
    /*!
    *@brief 获取错误字符串
    *@return 错误字符串
    */
    std::wstring GetErrorStr() const;

    /*!
    *@brief 设置错误字符串
    *@param[in] val，错误字符串
    */
    void SetErrorStr(const std::wstring &val);

    /*!
    *@brief 构造函数默认初始化为Num
    */
    UnitMap();

    /*!
    *@brief 默认析构函数
    */
    ~UnitMap();

    /*!
    *@brief 构造函数
    *@param[in] type，表达式单位类型
    */
    UnitMap(const ExprUnitType &type);

    /*!
    *@brief 拷贝构造函数
    *@param[in] types，源对象
    */
    UnitMap(const UnitMap &types);

    /*!
    *@brief 拷贝赋值运算符
    *@param[in] types，源对象
    */
    UnitMap& operator=(const UnitMap &types);

    /*!
    *@brief 初始化
    *@param[in] type，表达式单位类型
    *@param[in] value，对应的值
    *@return 成功返回true，失败返回false
    */
    bool InitialFrom(const ExprUnitType &type, const double &value = 1);

    /*!
    *@brief 判断是否有效的单位
    *@return 成功返回true，失败返回false
    */
    bool IsValid() const;

    /*!
    *@brief 判断是否数据
    *@return 是返回true，否返回false
    */
    bool IsNum() const;

    /*!
    *@brief 判断是否自然单位
    *@return 是返回true，否返回false
    */
    bool IsNaturalUnit() const;

    /*!
    *@brief 判断是否含有某单位类型
    *@param[in] type，表达式单位类型
    *@return 有返回true，没有返回false
    */
    bool MapHasType(const ExprUnitType &type);

    /*!
    *@brief 判断是否数据或自然单位
    *@return 是返回true，否返回false
    */
    bool IsNumOrNatureUnit() const;

    /*!
    *@brief 判断给定单位类型是否可计算
    *@param[in] type，表达式单位类型
    *@return 是返回true，否返回false
    */
    static bool IsCalculatable(const ExprUnitType &type);

    /*!
    *@brief 判断给定单位类型是否自然单位
    *@param[in] type，表达式单位类型
    *@return 是返回true，否返回false
    */
    static bool IsNaturalUnit(const ExprUnitType &type);

    /*!
    *@brief 获得单一单位
    *@return 如果是单一单位，则返回单位；如果非，则返回EUT_Invalid
    */
    ExprUnitType GetSingleUnit() const;

    /*!
    *@brief 清空
    */
    void Clear();

    /*!
    *@brief 拷贝自另一个对象
    *@param[in] typeMap，源对象
    */
    void GetCopyFrom(const UnitMap &typeMap);

    /*!
    *@brief 判断与给定对象是否相同
    *@param[in] typeMap，源对象
    *@return 相同返回true，不相同返回false
    */
    bool UnitIsSame(const UnitMap& typeMap) const;

    /*!
    *@brief 获取某个单位类型的幂值
    *@param[in] type，表达式单位类型
    *@return 单位幂值
    */
    double GetUnitCount(const ExprUnitType &type) const;

    /*!
    *@brief 查找所有单位类型
    *@param[out] types，表达式单位类型向量
    */
    void FindUnits(std::vector<ExprUnitType> &types) const;

    /*!
    *@brief 幂运算
    *@param[in] value，幂次
    */
    void Pow(const double &value);

    /*!
    *@brief 乘以一个单位
    *@param[in] type，被乘单位类型
    *@param[in] value，被乘单位幂值
    *@return 成功返回true，失败返回false
    */
    bool Multiply(const ExprUnitType &type, const double &value = 1);

    /*!
    *@brief 除以一个单位
    *@param[in] type，除数单位类型
    *@param[in] value，除数单位幂值
    *@return 成功返回true，失败返回false
    */
    bool Divided(const ExprUnitType &type, const double &value = 1);

    /*!
    *@brief 乘以一个表达式单位容器
    *@param[in] typeMap，被乘表达式单位容器对象
    *@return 成功返回true，失败返回false
    */
    bool Multiply(const UnitMap &typeMap);

    /*!
    *@brief 除以一个表达式单位容器
    *@param[in] typeMap，除数表达式单位容器对象
    *@return 成功返回true，失败返回false
    */
    bool Divided(const UnitMap &typeMap);

private:
#define Precisiondef 0.00001
    bool IsZero(const double &value)const;
    std::map<ExprUnitType, double> m_units;
    std::wstring m_errorStr;
};

// 单位助手类
class EXPR_UNITMAP_API UnitHelper
{
public:
    /*!
    *@brief 单位容器对象求和，并检查是否成功
    *@param[in] left，被加数单位容器对象
    *@param[in] right，加数单位容器对象
    *@param[out] result，结果单位容器对象
    *@return 成功返回true，失败返回false
    */
    static bool CheckUnitAdd(const UnitMap &left, const UnitMap &right, UnitMap &result);

    /*!
    *@brief 单位容器对象求差，并检查是否成功
    *@param[in] left，被减数单位容器对象
    *@param[in] right，减数单位容器对象
    *@param[out] result，结果单位容器对象
    *@return 成功返回true，失败返回false
    */
    static bool CheckUnitSubtract(const UnitMap &left, const UnitMap &right, UnitMap &result);
    
    /*!
    *@brief 单位容器对象求积，并检查是否成功
    *@param[in] left，被乘数单位容器对象
    *@param[in] right，乘数单位容器对象
    *@param[out] result，结果单位容器对象
    *@return 成功返回true，失败返回false
    */
    static bool CheckUnitMultiply(const UnitMap &left, const UnitMap &right, UnitMap &result);
    
    /*!
    *@brief 单位容器对象求商，并检查是否成功
    *@param[in] left，被除数单位容器对象
    *@param[in] right，除数单位容器对象
    *@param[out] result，结果单位容器对象
    *@return 成功返回true，失败返回false
    */
    static bool CheckUnitDivided(const UnitMap &left, const UnitMap &right, UnitMap &result);
    
    /*!
    *@brief 单位容器对象取模（求余），并检查是否成功
    *@param[in] left，被除数单位容器对象
    *@param[in] right，除数单位容器对象
    *@param[out] result，结果单位容器对象
    *@return 成功返回true，失败返回false
    */
    static bool CheckUnitModulus(const UnitMap &left, const UnitMap &right, UnitMap &result);
    
    /*!
    *@brief 单位容器对象进行比较，并检查是否成功
    *@param[in] left，比较对象1：单位容器对象
    *@param[in] right，比较对象2：单位容器对象
    *@param[out] result，结果单位容器对象
    *@return 成功返回true，失败返回false
    */
    static bool CheckUnitCompare(const UnitMap &left, const UnitMap &right, UnitMap &result);
};